package com.wolfsea.launcherdemo
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.view.MotionEvent
import android.view.View
import androidx.recyclerview.widget.RecyclerView

/**
 *@desc  PagingScrollHelper2
 *@author liuliheng
 *@time 2023/1/9  12:29
 **/
class PagingScrollHelper {

    private val mFlyingListener by lazy { PagingFlyingListener() }
    private val mScrollListener by lazy { PagingScrollListener() }
    private val mTouchListener by lazy { PagingTouchListener() }

    private var mOrientation = Orientation.HORIZONTAL

    private var offsetX = 0
    private var offsetY = 0
    private var startX = 0
    private var startY = 0
    private var lastPageIndex = 0

    private var firstTouch = true

    private var mRecyclerView: RecyclerView? = null
    private var mValueAnimator: ValueAnimator? = null
    private var mOnPageChangeListener: OnPageChangeListener? = null

    enum class Orientation(val value: Int) {
        HORIZONTAL(0),
        VERTICAL(1),
        NULL(2),
    }

    inner class PagingFlyingListener : RecyclerView.OnFlingListener() {
        override fun onFling(velocityX: Int, velocityY: Int): Boolean {
            if (mOrientation == Orientation.NULL) {
                return false
            }
            var pageIndex = getStartPageIndex()
            val startPoint: Int
            var endPoint: Int
            if (mOrientation == Orientation.VERTICAL) {
                startPoint = offsetY
                if (velocityY > 0) {
                    pageIndex++
                } else if (velocityY < 0) {
                    pageIndex--
                }
                //根据不同的速度判断需要滚动的方向
                //注意,此处有一个技巧,就是当速度为0的时候就滚动会开始的页面,即实现页面复位.
                endPoint = pageIndex * mRecyclerView?.height!!
            } else {
                startPoint = offsetX
                if (velocityX > 0) {
                    pageIndex++
                } else if (velocityX < 0) {
                    pageIndex--
                }
                endPoint = pageIndex * mRecyclerView?.width!!
            }
            endPoint = Math.max(endPoint, 0)

            //使用动画处理滚动
            if (mValueAnimator == null) {
                mValueAnimator = ValueAnimator.ofInt(startPoint, endPoint).apply {
                    duration = 300
                    addUpdateListener {
                        val nowPoint = it.animatedValue as Int
                        if (mOrientation == Orientation.VERTICAL) {
                            val dy = nowPoint - offsetY
                            //通过RecyclerView的scrollBy方法实现滚动
                            mRecyclerView?.scrollBy(0, dy)
                        } else {
                            val dx = nowPoint - offsetX
                            mRecyclerView?.scrollBy(dx, 0)
                        }
                    }
                    addListener(object : AnimatorListenerAdapter() {
                        override fun onAnimationEnd(animation: Animator?) {
                            super.onAnimationEnd(animation)
                            val currentPageIndex = getPageIndex()
                            if (currentPageIndex != lastPageIndex) {
                                lastPageIndex = currentPageIndex
                                mOnPageChangeListener?.onPageChange(currentPageIndex)
                            }
                            //修复双击item bug
                            mRecyclerView?.stopScroll()
                            startX = offsetX
                            startY = offsetY
                        }
                    })
                }
            } else {
                mValueAnimator?.apply {
                    cancel()
                    setIntValues(startPoint, endPoint)
                }
            }
            mValueAnimator?.start()
            return true
        }
    }

    inner class PagingScrollListener : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            //newState==0表示滚动停止,此时需要处理回滚
            if (newState == 0 && mOrientation != Orientation.NULL) {
                val move: Boolean
                var velocityX = 0
                var velocityY = 0
                if (mOrientation == Orientation.VERTICAL) {
                    val absY = Math.abs(offsetY - startY)
                    //如果滑动的距离超过屏幕的一半表示需要滑动到下一页
                    move = absY > mRecyclerView?.height!! / 2
                    velocityY = if (move) if ((offsetY - startY) < 0) -1000 else 1000 else 0
                } else {
                    val absX = Math.abs(offsetX - startX)
                    //如果滑动的距离超过屏幕的一半表示需要滑动到下一页
                    move = absX > mRecyclerView?.width!! / 2
                    velocityX = if (move) if ((offsetX - startX) < 0) -1000 else 1000 else 0
                }
                mFlyingListener.onFling(velocityX, velocityY)
            }
        }

        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
            super.onScrolled(recyclerView, dx, dy)
            //滚动结束记录滚动的偏移量
            offsetX += dx
            offsetY += dy
        }
    }

    inner class PagingTouchListener : View.OnTouchListener {
        override fun onTouch(view: View?, event: MotionEvent?): Boolean {
            //手指按下的时候记录开始滚动的坐标
            if (firstTouch) {
                //第一次touch可能是ACTION_MOVE或ACTION_DOWN,所以使用这种方式判断
                firstTouch = false
                startX = offsetX
                startY = offsetY
            }
            if (event?.action == MotionEvent.ACTION_UP || event?.action == MotionEvent.ACTION_CANCEL) {
                firstTouch = true
            }
            return false
        }
    }

    interface OnPageChangeListener {
        fun onPageChange(index: Int)
    }

    fun setUpRecyclerView(mRecyclerView: RecyclerView?) {
        if (mRecyclerView == null) {
            throw IllegalArgumentException("recycleView must be not null")
        }
        this.mRecyclerView = mRecyclerView
        this.mRecyclerView?.apply {
            //处理滑动
            onFlingListener = mFlyingListener
            //处理滚动
            addOnScrollListener(mScrollListener)
            //处理触摸事件
            setOnTouchListener(mTouchListener)
            //获取滚动方向
            updateLayoutManager()
        }
    }

    fun updateLayoutManager() {
        val layoutManager = mRecyclerView?.layoutManager
        layoutManager?.apply {
            mOrientation =
                if (canScrollVertically()) Orientation.VERTICAL
                else if (canScrollHorizontally()) Orientation.HORIZONTAL
                else Orientation.NULL
            if (mValueAnimator != null) {
                mValueAnimator!!.cancel()
            }
            startX = 0
            startY = 0
            offsetX = 0
            offsetY = 0
        }
    }

    fun scrollToPosition(position: Int) {
        if (mValueAnimator == null) {
            mFlyingListener.onFling(0, 0)
        } else {
            val startPoint = if (mOrientation == Orientation.HORIZONTAL) offsetX  else offsetY
            val endPoint =
                (if (mOrientation == Orientation.HORIZONTAL) mRecyclerView?.width!!
                else mRecyclerView?.height!!) * position
            if (startPoint != endPoint) {
                mValueAnimator?.apply {
                    setIntValues(startPoint, endPoint)
                    start()
                }
            }
        }
    }

    fun setOnPageChangeListener(mOnPageChangeListener: OnPageChangeListener?) {
        this.mOnPageChangeListener = mOnPageChangeListener
    }

    private fun getStartPageIndex(): Int {
        if (mRecyclerView?.width == 0 || mRecyclerView?.height == 0) {
            return 0
        }
        return when (mOrientation) {
            Orientation.HORIZONTAL -> {
                startX / mRecyclerView?.width!!
            }
            Orientation.VERTICAL -> {
                startY / mRecyclerView?.height!!
            }
            else -> {
                0
            }
        }
    }

    private fun getPageIndex(): Int {
        if (mRecyclerView?.width == 0 || mRecyclerView?.height == 0) {
            return 0
        }
        return when (mOrientation) {
            Orientation.HORIZONTAL -> {
                offsetX / mRecyclerView?.width!!
            }
            Orientation.VERTICAL -> {
                offsetY / mRecyclerView?.height!!
            }
            else -> {
                0
            }
        }
    }

}